{% extends "base.html" %}

{% block title %}执行记录 - XbyJob{% endblock %}

{% block content %}
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
    <h1 class="h2">执行记录</h1>
    <small class="text-muted align-self-center" id="autoRefreshStatus">
        <i class="fas fa-sync-alt fa-spin"></i> 自动刷新（30秒）
    </small>
</div>

<!-- 筛选器 -->
<div class="row mb-3">
    <div class="col-md-3">
        <select class="form-select" id="statusFilter">
            <option value="">全部状态</option>
            <option value="success">成功</option>
            <option value="failed">失败</option>
            <option value="running">运行中</option>
            <option value="pending">等待中</option>
        </select>
    </div>
    <div class="col-md-3">
        <select class="form-select" id="taskFilter">
            <option value="">全部任务</option>
        </select>
    </div>
    <div class="col-md-4">
        <input type="date" class="form-control" id="dateFilter">
    </div>
    <div class="col-md-2">
        <button type="button" class="btn btn-outline-primary w-100" onclick="applyFilters()">
            <i class="fas fa-filter me-1"></i>筛选
        </button>
    </div>
</div>

<!-- 执行记录列表 -->
<div class="card">
    <div class="card-body">
        <div class="table-responsive">
            <table class="table table-striped" id="executionsTable">
                <thead>
                    <tr>
                        <th>执行ID</th>
                        <th>任务名称</th>
                        <th>状态</th>
                        <th>开始时间</th>
                        <th>完成时间</th>
                        <th>耗时</th>
                        <th>执行节点</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td colspan="8" class="text-center">
                            <div class="spinner-border text-primary" role="status">
                                <span class="visually-hidden">加载中...</span>
                            </div>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
        
        <!-- 分页 -->
        <nav aria-label="执行记录分页">
            <ul class="pagination justify-content-center" id="pagination">
            </ul>
        </nav>
    </div>
</div>

<!-- 执行详情模态框 -->
<div class="modal fade" id="executionDetailModal" tabindex="-1">
    <div class="modal-dialog modal-xl">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">执行详情</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <div class="row mb-3">
                    <div class="col-md-6">
                        <p><strong>执行ID:</strong> <span id="detailExecutionId">-</span></p>
                        <p><strong>任务名称:</strong> <span id="detailTaskName">-</span></p>
                        <p><strong>状态:</strong> <span id="detailStatus">-</span></p>
                        <p><strong>退出码:</strong> <span id="detailExitCode">-</span></p>
                        <p><strong>重试次数:</strong> <span id="detailRetryCount">-</span></p>
                    </div>
                    <div class="col-md-6">
                        <p><strong>开始时间:</strong> <span id="detailStartTime">-</span></p>
                        <p><strong>完成时间:</strong> <span id="detailEndTime">-</span></p>
                        <p><strong>耗时:</strong> <span id="detailDuration">-</span></p>
                        <p><strong>执行节点:</strong> <span id="detailExecutor">-</span></p>
                    </div>
                </div>
                
                <div class="row">
                    <div class="col-12">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <h6><i class="fas fa-terminal me-1"></i>执行输出</h6>
                            <small class="text-muted" id="realtimeStatus">
                                <i class="fas fa-circle text-secondary"></i> 连接中...
                            </small>
                        </div>
                        <pre id="detailOutput" class="bg-light p-3 rounded" style="max-height: 500px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; word-wrap: break-word; border: 1px solid #dee2e6;">加载中...</pre>
                        <div class="mt-2">
                            <small class="text-muted">
                                <i class="fas fa-info-circle me-1"></i>
                                此处显示任务执行的所有输出内容（包括标准输出和错误输出）
                            </small>
                        </div>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-primary" onclick="downloadLogs()">
                    <i class="fas fa-download me-1"></i>下载日志
                </button>
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
            </div>
        </div>
    </div>
</div>

{% endblock %}

{% block extra_js %}
<script>
let currentPage = 1;
let currentFilters = {};
let currentExecution = null;

$(document).ready(function() {
    loadExecutions();
    loadTaskOptions();
    
    // 设置默认日期为今天
    $('#dateFilter').val(new Date().toISOString().split('T')[0]);
    
    // 每30秒自动刷新执行记录
    setInterval(function() {
        console.log('自动刷新执行记录列表...');
        loadExecutions(currentPage);
    }, 30000);
});

function loadExecutions(page = 1) {
    currentPage = page;
    
    // 显示刷新状态
    const refreshIcon = $('#autoRefreshStatus i');
    if (refreshIcon.length > 0) {
        refreshIcon.removeClass('fa-spin').addClass('fa-pulse');
    }
    
    const params = new URLSearchParams({
        page: page,
        per_page: 20,
        ...currentFilters
    });
    
    $('#executionsTable tbody').html(`
        <tr>
            <td colspan="8" class="text-center">
                <div class="spinner-border text-primary" role="status">
                    <span class="visually-hidden">加载中...</span>
                </div>
            </td>
        </tr>
    `);
    
    $.get('/api/executions?' + params.toString())
        .done(function(response) {
            if (response.success) {
                renderExecutions(response.data.executions);
                renderPagination(response.data.pagination);
            } else {
                showAlert('获取执行记录失败: ' + response.message, 'danger');
            }
        })
        .fail(function() {
            showAlert('网络错误，请稍后重试', 'danger');
        })
        .always(function() {
            // 恢复自动刷新状态
            if (refreshIcon.length > 0) {
                setTimeout(function() {
                    refreshIcon.removeClass('fa-pulse').addClass('fa-spin');
                }, 1000);
            }
        });
}

function renderExecutions(executions) {
    const tbody = $('#executionsTable tbody');
    tbody.empty();
    
    if (executions.length === 0) {
        tbody.append(`
            <tr>
                <td colspan="8" class="text-center text-muted">暂无执行记录</td>
            </tr>
        `);
        return;
    }
    
    executions.forEach(function(execution) {
        const statusBadge = getStatusBadge(execution.status);
        const startTime = new Date(execution.started_at).toLocaleString();
        const endTime = execution.completed_at ? new Date(execution.completed_at).toLocaleString() : '-';
        const duration = execution.duration ? formatDuration(execution.duration) : '-';
        const executor = execution.executor_host || '-';
        
        // 为运行中的任务添加停止按钮
        let stopButton = '';
        if (execution.status === 'running') {
            stopButton = `
                <button class="btn btn-outline-danger" onclick="stopExecution('${execution.execution_id}')" title="停止任务">
                    <i class="fas fa-stop"></i>
                </button>
            `;
        }
        
        tbody.append(`
            <tr>
                <td><code class="small">${execution.execution_id}</code></td>
                <td>
                    <div class="fw-bold">${execution.task_name || '-'}</div>
                    <small class="text-muted">ID: ${execution.task_id}</small>
                </td>
                <td>${statusBadge}</td>
                <td>${startTime}</td>
                <td>${endTime}</td>
                <td>${duration}</td>
                <td>${executor}</td>
                <td>
                    <div class="btn-group btn-group-sm">
                        <button class="btn btn-outline-primary" onclick="viewExecutionDetail('${execution.execution_id}')" title="详情">
                            <i class="fas fa-eye"></i>
                        </button>
                        <button class="btn btn-outline-info" onclick="viewTaskDetail(${execution.task_id})" title="查看任务">
                            <i class="fas fa-tasks"></i>
                        </button>
                        ${stopButton}
                    </div>
                </td>
            </tr>
        `);
    });
}

function renderPagination(pagination) {
    const nav = $('#pagination');
    nav.empty();
    
    if (pagination.pages <= 1) return;
    
    // 上一页
    nav.append(`
        <li class="page-item ${!pagination.has_prev ? 'disabled' : ''}">
            <a class="page-link" href="#" onclick="loadExecutions(${pagination.page - 1})">上一页</a>
        </li>
    `);
    
    // 页码
    const startPage = Math.max(1, pagination.page - 2);
    const endPage = Math.min(pagination.pages, pagination.page + 2);
    
    for (let i = startPage; i <= endPage; i++) {
        nav.append(`
            <li class="page-item ${i === pagination.page ? 'active' : ''}">
                <a class="page-link" href="#" onclick="loadExecutions(${i})">${i}</a>
            </li>
        `);
    }
    
    // 下一页
    nav.append(`
        <li class="page-item ${!pagination.has_next ? 'disabled' : ''}">
            <a class="page-link" href="#" onclick="loadExecutions(${pagination.page + 1})">下一页</a>
        </li>
    `);
}

function loadTaskOptions() {
    $.get('/api/tasks?per_page=1000')
        .done(function(response) {
            if (response.success) {
                const select = $('#taskFilter');
                response.data.tasks.forEach(function(task) {
                    select.append(`<option value="${task.id}">${task.name}</option>`);
                });
            }
        });
}

function applyFilters() {
    currentFilters = {};
    
    const status = $('#statusFilter').val();
    if (status) currentFilters.status = status;
    
    const taskId = $('#taskFilter').val();
    if (taskId) currentFilters.task_id = taskId;
    
    const date = $('#dateFilter').val();
    if (date) currentFilters.date = date;
    
    loadExecutions(1);
}



function viewExecutionDetail(executionId) {
    currentExecution = executionId;
    
    // 如果之前在查看其他执行，先离开那个房间
    if (currentViewingExecutionId && currentViewingExecutionId !== executionId) {
        leaveExecutionRoom(currentViewingExecutionId);
    }
    
    // 设置当前查看的执行ID
    currentViewingExecutionId = executionId;
    
    // 加入新的执行房间以接收实时更新
    joinExecutionRoom(executionId);
    
    $.get(`/api/executions/${executionId}`)
        .done(function(response) {
            if (response.success) {
                const execution = response.data;
                
                $('#detailExecutionId').text(execution.execution_id);
                $('#detailTaskName').text(execution.task_name || '未知任务');
                $('#detailStatus').html(getStatusBadge(execution.status));
                $('#detailExitCode').text(execution.exit_code || '-');
                $('#detailRetryCount').text(execution.retry_count || 0);
                $('#detailStartTime').text(execution.started_at ? new Date(execution.started_at).toLocaleString() : '-');
                $('#detailEndTime').text(execution.completed_at ? new Date(execution.completed_at).toLocaleString() : '-');
                
                if (execution.duration) {
                    $('#detailDuration').text(formatDuration(execution.duration));
                } else {
                    $('#detailDuration').text('-');
                }
                
                $('#detailExecutor').text(execution.executor_host || '-');
                
                // 合并显示标准输出和错误输出
                let combinedOutput = '';
                if (execution.stdout && execution.stdout.trim()) {
                    combinedOutput += execution.stdout;
                }
                if (execution.stderr && execution.stderr.trim()) {
                    if (combinedOutput) {
                        combinedOutput += '\n\n--- 错误输出 ---\n';
                    }
                    combinedOutput += execution.stderr;
                }
                
                if (!combinedOutput.trim()) {
                    combinedOutput = '暂无输出内容';
                }
                
                $('#detailOutput').text(combinedOutput);
                
                // 自动滚动到底部
                const outputElement = document.getElementById('detailOutput');
                if (outputElement) {
                    outputElement.scrollTop = outputElement.scrollHeight;
                }
                
                $('#executionDetailModal').modal('show');
            } else {
                showAlert('获取执行详情失败: ' + response.message, 'danger');
            }
        })
        .fail(function() {
            showAlert('网络错误，无法获取执行详情', 'danger');
        });
}

function viewTaskDetail(taskId) {
    window.location.href = `/dashboard/tasks/${taskId}/detail`;
}

function downloadLogs() {
    if (!currentExecution) return;
    
    // 创建日志内容
    const output = $('#detailOutput').text();
    
    const logContent = `执行ID: ${currentExecution}
开始时间: ${$('#detailStartTime').text()}
完成时间: ${$('#detailEndTime').text()}
状态: ${$('#detailStatus').text()}
退出码: ${$('#detailExitCode').text()}
重试次数: ${$('#detailRetryCount').text()}

=== 执行输出 ===
${output}
`;
    
    // 下载文件
    const blob = new Blob([logContent], { type: 'text/plain' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `execution_${currentExecution}_log.txt`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
}

function getStatusBadge(status) {
    const badges = {
        'success': '<span class="badge bg-success">成功</span>',
        'failed': '<span class="badge bg-danger">失败</span>',
        'running': '<span class="badge bg-primary">运行中</span>',
        'pending': '<span class="badge bg-warning">等待中</span>',
        'cancelled': '<span class="badge bg-secondary">取消</span>'
    };
    return badges[status] || `<span class="badge bg-secondary">${status}</span>`;
}

function formatDuration(seconds) {
    if (seconds < 60) {
        return seconds.toFixed(2) + '秒';
    } else if (seconds < 3600) {
        return Math.floor(seconds / 60) + '分' + Math.floor(seconds % 60) + '秒';
    } else {
        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        return hours + '小时' + minutes + '分';
    }
}

function showAlert(message, type) {
    // 使用基础模板中定义的全局showMessage函数（即showToast）
    if (typeof window.showMessage === 'function') {
        // 映射类型到Toast支持的类型
        let toastType = type;
        switch(type) {
            case 'danger':
                toastType = 'error';
                break;
            case 'warning':
                toastType = 'warning';
                break;
            case 'success':
                toastType = 'success';
                break;
            default:
                toastType = 'info';
        }
        showMessage(message, toastType, 3000);
    } else {
        // 如果全局函数不可用，回退到原来的实现
        const alertHtml = `
            <div class="alert alert-${type} alert-dismissible fade show" role="alert">
                ${message}
                <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
            </div>
        `;
        
        $('.container-fluid').prepend(alertHtml);
        
        setTimeout(function() {
            $('.alert').alert('close');
        }, 3000);
    }
}

// 停止执行任务
function stopExecution(executionId) {
    if (!confirm('确定要停止这个正在运行的任务吗？')) {
        return;
    }
    
    $.ajax({
        url: `/api/executions/${executionId}/stop`,
        method: 'POST'
    })
    .done(function(response) {
        if (response.success) {
            showAlert('任务已停止', 'success');
            // 刷新执行记录
            setTimeout(function() {
                loadExecutions(currentPage);
            }, 1000);
        } else {
            showAlert('停止失败: ' + response.message, 'danger');
        }
    })
    .fail(function() {
        showAlert('网络错误，请稍后重试', 'danger');
    });
}

// WebSocket相关变量和函数
var socket = null;
var currentViewingExecutionId = null;

// 初始化WebSocket连接
function initWebSocket() {
    try {
        console.log('初始化WebSocket连接...');
        socket = io();
        
        socket.on('connect', function() {
            console.log('WebSocket连接成功');
            updateRealtimeStatus(true);
        });
        
        socket.on('disconnect', function() {
            console.log('WebSocket连接断开');
            updateRealtimeStatus(false);
        });
        
        socket.on('execution_output', function(data) {
            console.log('收到实时输出:', data);
            handleRealtimeOutput(data);
        });
        
        socket.on('execution_status_change', function(data) {
            console.log('收到执行状态变化:', data);
            // 刷新执行列表
            loadExecutions();
        });
        
    } catch (error) {
        console.error('WebSocket初始化失败:', error);
    }
}

// 处理实时输出
function handleRealtimeOutput(data) {
    // 如果当前正在查看这个执行的日志，实时更新输出
    if (currentViewingExecutionId && currentViewingExecutionId == data.execution_id) {
        console.log('执行ID匹配，追加实时输出');
        appendRealtimeOutput(data);
    }
}

// 追加实时输出到日志显示区域
function appendRealtimeOutput(data) {
    const outputElement = $('#detailOutput');
    if (outputElement.length > 0) {
        let currentContent = outputElement.text();
        
        if (data.output_type === 'stdout' && data.content) {
            // 直接追加标准输出
            currentContent += data.content;
        } else if (data.output_type === 'stderr' && data.content) {
            // 如果是第一次添加错误输出，添加分隔符
            if (currentContent && !currentContent.includes('--- 错误输出 ---')) {
                currentContent += '\n\n--- 错误输出 ---\n';
            }
            currentContent += data.content;
        }
        
        outputElement.text(currentContent);
        
        // 自动滚动到底部
        const outputDom = outputElement[0];
        if (outputDom) {
            outputDom.scrollTop = outputDom.scrollHeight;
        }
    }
}

// 加入执行房间（当查看执行日志时）
function joinExecutionRoom(executionId) {
    if (socket && socket.connected) {
        socket.emit('join_execution', {execution_id: executionId});
        console.log('已加入执行房间:', executionId);
    }
}

// 离开执行房间
function leaveExecutionRoom(executionId) {
    if (socket && socket.connected) {
        socket.emit('leave_execution', {execution_id: executionId});
        console.log('已离开执行房间:', executionId);
    }
}

// 更新实时状态指示器
function updateRealtimeStatus(connected) {
    const statusElement = $('#realtimeStatus');
    if (statusElement.length > 0) {
        if (connected) {
            statusElement.html('<i class="fas fa-circle text-success"></i> 实时推送');
        } else {
            statusElement.html('<i class="fas fa-circle text-danger"></i> 连接断开');
        }
    }
}

// 页面加载完成后初始化WebSocket
$(document).ready(function() {
    initWebSocket();
    
    // 监听模态框关闭事件
    $('#executionDetailModal').on('hidden.bs.modal', function() {
        if (currentViewingExecutionId) {
            leaveExecutionRoom(currentViewingExecutionId);
            currentViewingExecutionId = null;
        }
    });
});
</script>

<!-- Socket.IO 客户端库 -->
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
{% endblock %}